#include <stdio.h>
#include <stdlib.h>
#include "ast.h"
#include "sym.h"
#include "error.h"
#include "trace.h"
/*
0 Not exist 
1 Exist
Validate the syntax tree with all the e-llicite rules
*/
int validateSyntax(ASTTREE tree,SYMTABLE sym)
{
	
	int type = tree->type;
	SYMTABLE node;

	TraceMsg("validateSyntax",humanReadableNodeType(type));
	switch(type) 
	{
		case AT_PROG: return validateSyntax(tree->right,sym);	
		case AT_FUNC: return validateSyntax(tree->right,sym);
		case AT_FUNC_HEAD: return 0;
		
		case AT_FUNC_BODY:
			if ( validateSyntax(tree->left,sym) == 0)
			{
				return validateSyntax(tree->right,sym);
			}
			else return Error(101,"Missing variable declaration bloc");
			
		case AT_DECLARE:
			return validateSyntax(tree->right,sym);
		case AT_IMPL:
            if(tree->left != NULL)
                return validateInstructionList(tree->left,sym,AT_UNKNOWN);
            else
                return OK;
					
		case AT_ID: 
			printf("%d %s %d %d ",tree->vtype,tree->sval,tree->ival , tree->bval);
			node = alreadyIsSymbol(sym, tree->sval);
			if (node == NULL)
			{
				return Error(2,"The variable is not defined");
			}
			else
			{
				printf("Found node with vtype %d\n", node->idType);
			}
			return OK;
		default: 
			return 0;
			break;
	}

}


int validateInstructionList(ASTTREE tree,SYMTABLE sym, int currentType)
{
		int leftType;
		int rightType;
		int result;
	TraceMsg("validateInstructionList",humanReadableNodeType(tree->type));
	switch(tree->type)
	{
        case AT_ID: 
			if ( GetType(tree,sym) != KO /*&& GetType(tree,sym) == currentType*/) return OK;
			else return Error(-102,"Missing declared variable");
		case AT_NB: 
			if ( currentType == AT_NB) return OK;
			else return KO;
		case AT_BOOL:
			if ( currentType == AT_BOOL) return OK;
			else return KO;
			
        case AT_ILIST:
			if ( tree->left != NULL)
			{
				//if ( validateInstructionList(tree->left,sym) == OK && tree->right != NULL)
				if ( currentType == AT_UNKNOWN) currentType = tree->left->vtype;
					result = validateInstructionList(tree->left,sym,currentType);
					//printf("Result L %d \n",result);
					if ( result == KO)
						return result;
			}
			
			if ( tree->right != NULL)
            {
				if ( currentType == AT_UNKNOWN) currentType = tree->right->vtype;
                result = validateInstructionList(tree->right,sym,currentType);
				//printf("Result R %d \n",result);
					return result;
            }
            else
                return KO;

		case AT_OPADD:
            
            //printf("type left %d = type righ %d", GetType(tree->left,sym), GetType(tree->right,sym));
			if ( currentType == AT_UNKNOWN) currentType = AT_NB;
			if ( currentType != AT_NB) return Error(-100,"Could not assign");

			leftType = GetType(tree->right,sym);
			rightType = GetType(tree->left,sym);
			
			if ( leftType == KO || rightType == KO || leftType == AT_BOOL || rightType == AT_BOOL)
				return KO;
				
			if ( leftType == AT_NB && rightType == AT_NB)
				return OK;
			else
			{
				if ( validateInstructionList(tree->right, sym, AT_NB) == OK)
					return validateInstructionList(tree->left, sym, AT_NB);
			}
        case AT_OPMUL:
			if ( currentType == AT_UNKNOWN) currentType = AT_NB;
			if ( currentType != AT_NB) return Error(-100,"Could not assign");
			
			leftType = GetType(tree->right,sym);
			rightType = GetType(tree->left,sym);
			if ( leftType == KO || rightType == KO || leftType == AT_BOOL || rightType == AT_BOOL)
				return KO;
				
			if ( leftType == AT_NB && rightType == AT_NB)
				return OK;
			else
			{
				if ( validateInstructionList(tree->right, sym, AT_NB) == OK)
					return validateInstructionList(tree->left, sym, AT_NB);
			}
        case AT_OPDIV:
			if ( currentType == AT_UNKNOWN) currentType = AT_NB;
			if ( currentType != AT_NB) return Error(-100,"Could not assign");
			
			leftType = GetType(tree->right,sym);
			rightType = GetType(tree->left,sym);
			if ( leftType == KO || rightType == KO || leftType == AT_BOOL || rightType == AT_BOOL)
				return KO;
				
			if ( leftType == AT_NB && rightType == AT_NB)
				return OK;
			else
			{
				if ( validateInstructionList(tree->right, sym, AT_NB) == OK)
					return validateInstructionList(tree->left, sym, AT_NB);
			}
        case AT_OPSUB:
			if ( currentType == AT_UNKNOWN) currentType = AT_NB;
			if ( currentType != AT_NB) return Error(-100,"Could not assign");
			
			leftType = GetType(tree->right,sym);
			rightType = GetType(tree->left,sym);
			if ( leftType == KO || rightType == KO || leftType == AT_BOOL || rightType == AT_BOOL)
				return KO;
				
			if ( leftType == AT_NB && rightType == AT_NB)
				return OK;
			else
			{
				if ( validateInstructionList(tree->right, sym, AT_NB) == OK)
					return validateInstructionList(tree->left, sym, AT_NB);
			}
        case AT_OR:
			if ( currentType == AT_UNKNOWN) currentType = AT_BOOL;
			if ( currentType != AT_BOOL) return Error(-100,"Could not assign");
			
			leftType = GetType(tree->right,sym);
			rightType = GetType(tree->left,sym);
			if ( leftType == KO || rightType == KO || leftType == AT_NB || rightType == AT_NB)
				return KO;
				
			if ( leftType == AT_BOOL && rightType == AT_BOOL)
				return OK;
			else
			{
				if ( validateInstructionList(tree->right, sym, AT_BOOL) == OK)
					return validateInstructionList(tree->left, sym, AT_BOOL);
			}
        case AT_AND:
			if ( currentType == AT_UNKNOWN) currentType = AT_BOOL;
			if ( currentType != AT_BOOL) return Error(-100,"Could not assign");
			
			leftType = GetType(tree->right,sym);
			rightType = GetType(tree->left,sym);
			if ( leftType == KO || rightType == KO || leftType == AT_NB || rightType == AT_NB)
				return KO;
				
			if ( leftType == AT_BOOL && rightType == AT_BOOL)
				return OK;
			else
			{
				if ( validateInstructionList(tree->right, sym, AT_BOOL) == OK)
					return validateInstructionList(tree->left, sym, AT_BOOL);
			}
        case AT_NOT:
			if ( currentType == AT_UNKNOWN) currentType = AT_BOOL;
			if ( currentType != AT_BOOL) return Error(-100,"Could not assign");
			
			rightType = GetType(tree->right,sym);
			if ( rightType == KO || rightType == AT_NB)
				return KO;
				
			if ( rightType == AT_BOOL)
				return OK;
			else
			{
				return validateInstructionList(tree->right, sym, AT_BOOL);
			}
        case AT_LT: //TODO manage complex element
			if ( currentType == AT_UNKNOWN) currentType = AT_BOOL;
			if ( currentType != AT_BOOL) return Error(-100,"Could not assign");

			if ( GetType(tree->left,sym) == AT_NB && GetType(tree->right,sym) == AT_NB)
				return OK;
			else
				return KO;
        case AT_LE:
			if ( currentType == AT_UNKNOWN) currentType = AT_BOOL;
			if ( currentType != AT_BOOL) return Error(-100,"Could not assign");

			if ( GetType(tree->left,sym) == AT_NB && GetType(tree->right,sym) == AT_NB)
				return OK;
			else
				return KO;
        case AT_OPEQ:
			if ( currentType == AT_UNKNOWN) currentType = AT_BOOL;
			if ( currentType != AT_BOOL) return Error(-100,"Could not assign");
			
			rightType = GetType(tree->right,sym);
			leftType = GetType(tree->left,sym);
			if ( leftType == KO || rightType == KO || (leftType == AT_NB && rightType == AT_BOOL) || (leftType == AT_BOOL && rightType == AT_NB))
				return KO;
				
			if (( leftType == AT_BOOL && rightType == AT_BOOL) || (leftType == AT_NB && rightType == AT_NB))
				return OK;
			else
			{
				if ( validateInstructionList(tree->right, sym, AT_UNKNOWN) == OK)
					return validateInstructionList(tree->left, sym, AT_UNKNOWN);
			}
        case AT_NEG:
			if ( GetType(tree->right,sym) == AT_NB )
				return OK;
			if ( GetType(tree->right,sym) == AT_UNKNOWN )
				return validateInstructionList(tree->right,sym,AT_NB);
		case AT_OPASS:
			leftType = GetType(tree->left,sym);
			if ( leftType == KO) return Error(1,"Missing declared variable");	// Var is not in the declared bloc
			return validateInstructionList(tree->right,sym,leftType);
		case AT_OPWRITE:
				return validateInstructionList(tree->left,sym,tree->left->vtype);
		case AT_OPREAD:
			if (GetType(tree->left,sym) != KO && GetType(tree->left,sym) != AT_UNKNOWN)
				return OK;
			else return KO;
		case AT_RETURN:
			return OK;
        case AT_FUNC:
            return OK;
        case AT_IF:
            if ( currentType == AT_UNKNOWN) currentType = AT_BOOL;
			if ( currentType != AT_BOOL) return Error(-118,"Invalid Type");
			
			leftType = GetType(tree->left,sym);
			if ( leftType == KO || leftType == AT_NB)
				return KO;
            
			if ( leftType == AT_BOOL )
				return OK;
			else
			{
				if ( validateInstructionList(tree->left, sym, AT_BOOL) == OK)
                {
                    if(tree->right != NULL)//if body empty or not
                        return validateInstructionList(tree->right, sym, AT_UNKNOWN);
                    else return OK; 
                    
                }
                else
                    return KO;
			}
        case AT_IF_BODY:
            if(tree->right != NULL)//if body empty or not
                if( validateInstructionList(tree->right, sym, AT_UNKNOWN)==OK)
                    if(tree->left != NULL)//if body empty or not
                       return validateInstructionList(tree->left, sym, AT_UNKNOWN);
                    else
                       return OK;
                else
                    return KO;
            else
                if(tree->left != NULL)//if body empty or not
                    return validateInstructionList(tree->left, sym, AT_UNKNOWN);
                else
                    return OK;
                
        case AT_WHILE:
            if ( currentType == AT_UNKNOWN) currentType = AT_BOOL;
			if ( currentType != AT_BOOL) return Error(-119,"Invalid Type");
			
			leftType = GetType(tree->left,sym);
			if ( leftType == KO || leftType == AT_NB)
				return KO;
            
			if ( leftType == AT_BOOL )
				return OK;
			else
			{
				if ( validateInstructionList(tree->left, sym, AT_BOOL) == OK)
                {
                    if(tree->right != NULL)//if body empty or not
                        return validateInstructionList(tree->right, sym, AT_UNKNOWN);
                    else return OK; 
                        
                }
                else
                    return KO;
			}
        case AT_ARGS:
            return OK;
        case AT_ISET:
            return OK;
        case AT_VOID:
            return OK;
        case AT_FUNC_CALL:
            return OK;
		default:
			printf("%d",tree->type);
			return Error(-100,"No case for this node");
	}
	return OK;
}

int GetType(ASTTREE tree,SYMTABLE sym)
{
	if ( tree->type == AT_ID )
	{
		TraceMsg2("GetType"," AT_ID check",tree->sval);
		SYMTABLE symNode = alreadyIsSymbol(sym, tree->sval);
		if ( symNode == NULL)
			return KO;
		else return symNode->idType;
	}
	else if(tree->type == AT_BOOL || tree->type == AT_NB || tree->type == AT_NEG)
    {
		return tree->vtype;
    }
    else 
    {
        return AT_UNKNOWN;
	}
}
/*
 
 
int validateType(ASTTREE tree, SYMTABLE sym, int currentType)
{
    if(tree->left != NULL)
	{
        int leftType = GetType(tree->left,sym);
		TraceNb("validateType NOL",leftType);
		
		if ( leftType == KO) return Error(1,"Missing declared variable");	// Var is not in the declared bloc
		
        int rightType = validateType(tree->right,sym,leftType);
		
		TraceMsg("validateType LEFT",humanReadableNodeType(leftType));
		TraceMsg("validateType RIGHT",humanReadableNodeType(rightType));
		
        if(leftType == rightType)
            if(currentType != AT_UNKNOWN && currentType == leftType)
                return OK;
            else
			{
				printf("Current %d - %d ",currentType,GetType(tree,sym));
				if ( currentType == AT_UNKNOWN && currentType == GetType(tree,sym))	// AT_ID ?
					return OK;
					
				printf("bla\n ");
                return KO;
			}
    }else if(tree->right != NULL)
	{
		printf("souris\n");
        return validateType(tree->right,sym,tree->vtype);
    }
	else
	{
		printf("aaaaa\n");
        return KO;
    }
}*/
